/**
 * 
 */
package com.alphasystem.commerce.common.annotation.apt;

import static org.apache.commons.lang.StringUtils.isEmpty;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.alphasystem.commerce.ui.cmc.AttributeType;
import com.alphasystem.commerce.ui.cmc.ComponentType;
import com.alphasystem.commerce.ui.cmc.PropertyType;

/**
 * @author sali
 * 
 */
public class DomPersistenceHelperImpl implements PersistenceHelper {

	private void addAttribute(Element element, String attributeName,
			String attributeValue) {
		if (!isEmpty(attributeValue)) {
			element.setAttribute(attributeName, attributeValue);
		}
	}

	private Element createAttributeElement(Document document,
			AttributeType attributeType) {
		Element attributeElement = document.createElement("ns:attribute");

		addAttribute(attributeElement, "name", attributeType.getName());
		addAttribute(attributeElement, "value", attributeType.getValue());

		return attributeElement;
	}

	private Element createComponentElement(Document document,
			ComponentType componentType) {
		Element componentElement = document.createElement("ns:component");

		List<PropertyType> propertyTypes = componentType.getProperty();
		for (PropertyType propertyType : propertyTypes) {
			componentElement.appendChild(createPropertyElement(document,
					propertyType));
		}
		addAttribute(componentElement, "typeName", componentType.getTypeName());
		addAttribute(componentElement, "resourceBundle",
				componentType.getResourceBundle());
		addAttribute(componentElement, "displayName",
				componentType.getDisplayName());

		return componentElement;
	}

	private Element createPropertyElement(Document document,
			PropertyType propertyType) {
		Element propertyElement = document.createElement("ns:property");

		List<AttributeType> attributeTypes = propertyType.getAttribute();
		for (AttributeType attributeType : attributeTypes) {
			propertyElement.appendChild(createAttributeElement(document,
					attributeType));
		}
		addAttribute(propertyElement, "fieldName", propertyType.getFieldName());
		addAttribute(propertyElement, "resourceBundle",
				propertyType.getResourceBundle());
		addAttribute(propertyElement, "displayName",
				propertyType.getDisplayName());
		addAttribute(propertyElement, "category", propertyType.getCategory());
		addAttribute(propertyElement, "required",
				String.valueOf(propertyType.isRequired()));
		addAttribute(propertyElement, "dataType", propertyType.getDataType());
		String componentType = propertyType.getComponentType();
		if (!isEmpty(componentType)) {
			addAttribute(propertyElement, "componentType", componentType);
		}
		return propertyElement;
	}

	public void saveAsXml(File outFile, Map<String, ComponentType> components) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;

		// create xml document
		try {
			builder = factory.newDocumentBuilder();
			Document document = builder.newDocument();
			document.setXmlVersion("1.0");

			Element root = document.createElementNS(
					"http://www.alphasystem.com/xml/data/types/uiframework",
					"ns:components");

			document.appendChild(root);

			for (Entry<String, ComponentType> entry : components.entrySet()) {
				ComponentType componentType = entry.getValue();
				Element componentElement = createComponentElement(document,
						componentType);
				root.appendChild(componentElement);
			}

			// save to file
			TransformerFactory tf = TransformerFactory.newInstance();
			tf.setAttribute("indent-number", 2);
			Transformer transformer = tf.newTransformer();
			// if tiger would just format it :(
			// formatting bug in tiger
			// (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446)
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

			Source source = new DOMSource(document);
			Result result = new StreamResult(new OutputStreamWriter(
					new FileOutputStream(outFile)));
			transformer.transform(source, result);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
